// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... namespace LargoCommon.Music { using LargoCommon.Interfaces; using System; using System.Collections; using System.Collections.ObjectModel; using System.Diagnostics.Contracts; using System.Globalization; using System.Text; using System.Xml.Serialization; /// /// Binary Structure. /// [Serializable] [XmlRoot] public class BinaryStructure : GeneralOwner, IComparable, IGeneralStruct { #region Fields /// /// Bit Array. /// private BitArray bitArray; /// /// Structural Code. /// private string structuralCode; /// /// General system. /// private GeneralSystem gsystem; //// readonly /// Number of nonzero bits, number of rotations. private byte level; #endregion #region Constructors /// Initializes a new instance of the BinaryStructure class. Serializable. public BinaryStructure() { } /// Initializes a new instance of the BinaryStructure class. /// Abstract system. /// Structural code. public BinaryStructure(GeneralSystem givenSystem, string givenStructuralCode) { Contract.Requires(givenSystem != null); this.gsystem = givenSystem; this.SetStructuralCode(givenStructuralCode); this.DetermineLevel(); //// 2014/12 Time optimization //// this.CheckInstance(); } /// Initializes a new instance of the BinaryStructure class. /// Abstract system. /// Bit array. public BinaryStructure(GeneralSystem givenSystem, BitArray givenBitArray) { Contract.Requires(givenSystem != null); this.gsystem = givenSystem; this.bitArray = givenBitArray; this.DetermineLevel(); //// 2014/12 Time optimization //// this.CheckInstance(); } /// Initializes a new instance of the BinaryStructure class. /// Abstract system. /// Number of structure. public BinaryStructure(GeneralSystem givenSystem, long number) { this.gsystem = givenSystem ?? throw new InvalidOperationException("G-system is null."); this.DecimalNumber = number; this.SetNumber(number); this.DetermineLevel(); //// 2014/12 Time optimization //// this.CheckInstance(); } /// Initializes a new instance of the BinaryStructure class. /// Binary structure. public BinaryStructure(BinaryStructure structure) { Contract.Requires(structure != null); this.gsystem = structure.GSystem; this.bitArray = (BitArray)structure.BitArray.Clone(); this.level = structure.Level; //// 2014/12 Time optimization //// this.CheckInstance(); } #endregion #region Properties /// Gets BitArray. /// Property description. public BitArray BitArray { get { Contract.Ensures(Contract.Result() != null); if (this.bitArray == null) { throw new InvalidOperationException("Bit array is null."); } return this.bitArray; } } /// Gets or sets Number. /// Property description. public long Number { get; set; } /// Gets or sets DecimalNumber. /// Property description. public decimal DecimalNumber { get; set; } /// Gets or sets abstract G-System. /// Property description. [XmlIgnore] //// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Contracts", "Ensures")] public GeneralSystem GSystem { get { Contract.Ensures(Contract.Result() != null); Contract.Ensures(Contract.Result().Order > 0); if (this.gsystem == null) { throw new InvalidOperationException("G-system is null."); } return this.gsystem; } set => this.gsystem = value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value)); } /// Gets or sets modality. /// Property description. [XmlIgnore] public IGeneralStruct Modality { get; set; } /// Gets or sets level, i.e. number of ones in the structure. /// Property description. [XmlAttribute] public byte Level { get => this.level; set { this.level = value; this.SetProperty(GenProperty.Level, this.level); } } /// /// Gets or sets the occurrence - for statistical reasons (material,...). May be moved to properties... /// /// /// The occurrence. /// public int Occurrence { get; set; } /// /// Gets or sets the class code. /// /// /// The class code. /// public string ClassCode { get; set; } #endregion #region Schemas /// Gets positions of nonzero bits. /// Property description. [XmlIgnore] public Collection BitPlaces { get { Contract.Ensures(Contract.Result>() != null); var places = new Collection(); var order = this.GSystem.Order; for (byte e = 0; e < order; e++) { if (this.IsOn(e)) { places.Add(e); } } return places; } } /// Gets distances of nonzero bits. /// Property description. [XmlIgnore] public Collection BitDistances { get { var places = this.BitPlaces; var distances = new Collection(); var order = this.GSystem.Order; if (this.Level > 1) { byte p = 0, r = 0; var lastL = (byte)(this.Level - 1); for (byte lev = 0; lev < lastL; lev++) { if (lev + 1 < places.Count) { p = places[lev]; //// p = this.PlaceAtLevel(lev); r = places[lev + 1]; //// r = this.PlaceAtLevel((byte)(lev + 1)); } distances.Add(this.GSystem.FormalLength(r - p)); //// + order } if (lastL < places.Count) { p = places[lastL]; //// p = this.PlaceAtLevel(lastL); } if (places.Count > 0) { r = places[0]; //// r = this.PlaceAtLevel(0); } distances.Add(this.GSystem.FormalLength(r - p)); //// + order } else { distances.Add(order); } return distances; } } /// /// Gets the number. /// /// Returns value. public long GetNumber { get { //// Contract.Requires(this.BitArray != null); if (this.bitArray == null) { return 0; } var r = this.bitArray.Count; long n = 0; for (byte bit = 0; bit < r; bit++) { if (this.bitArray[bit]) { n |= BinaryNumber.BitAt(bit); } } return n; } } /// /// Gets the class structure. /// /// Returns value. public BinaryStructure GetClassStructure { get { //// Contract.Requires(this.BitArray != null); if (this.bitArray == null) { return null; } var number = this.GetNumber; var classNumber = BinaryNumber.DetermineClassNumber(this.GSystem.Order, number); var chs = new BinaryStructure(this.GSystem, classNumber); return chs; } } /// /// Gets StructuralCode. /// /// Returns value. /// Property description. public string GetStructuralCode => this.structuralCode ?? (this.structuralCode = this.DetermineStructuralCode()); #endregion #region Static functions #endregion #region Static operators //// TICS rule 7@526: Reference types should not override the equality operator (==) //// public static bool operator ==(BinaryStructure structure1, BinaryStructure structure2) { return object.Equals(structure1, structure2); } //// public static bool operator !=(BinaryStructure structure1, BinaryStructure structure2) { return !object.Equals(structure1, structure2); } //// but TICS rule 7@530: Class implements interface 'IComparable' but does not implement '==' and '!='. /// /// Implements the operator <. /// /// The object1. /// The object2. /// /// Returns value. /// public static bool operator <(BinaryStructure object1, BinaryStructure object2) { if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) { return object1.Number < object2.Number; } return false; } /// /// Implements the operator >. /// /// The object1. /// The object2. /// /// Returns value. /// public static bool operator >(BinaryStructure object1, BinaryStructure object2) { if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) { return object1.Number > object2.Number; } return false; } /// /// Implements the operator <=. /// /// The object1. /// The object2. /// /// Returns value. /// public static bool operator <=(BinaryStructure object1, BinaryStructure object2) { if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) { return object1.Number <= object2.Number; } return false; } /// /// Implements the operator >=. /// /// The object1. /// The object2. /// /// Returns value. /// public static bool operator >=(BinaryStructure object1, BinaryStructure object2) { if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) { return object1.Number >= object2.Number; } return false; } #endregion #region Comparison /// Support sorting according to level and number. /// Object to be compared. /// Returns value. public override int CompareTo(object value) { if (!(value is BinaryStructure bs)) { return 0; } if (this.Level < bs.Level) { return -1; } return this.Level > bs.Level ? 1 : string.Compare(this.BitArray.ToString(), bs.BitArray.ToString(), StringComparison.Ordinal); //// This kills the DataGrid //// throw new ArgumentException("Object is not a BinaryStructure"); } /// Test of equality. /// Object to be compared. /// Returns value. public override bool Equals(object obj) { //// check null (this pointer is never null in C# methods) if (object.ReferenceEquals(obj, null)) { return false; } if (object.ReferenceEquals(this, obj)) { return true; } if (this.GetType() != obj.GetType()) { return false; } return this.CompareTo(obj) == 0; } /// Support of comparison. /// Returns value. public override int GetHashCode() { return this.BitArray.GetHashCode(); } #endregion #region Public virtual methods /// Test of emptiness. /// Returns value. public virtual bool IsEmptyStruct() { return this.level == 0; } /// Validity test. /// Returns value. public virtual bool IsValidStruct() { return true; } /// Evaluate properties of the structure. Used in descendant objects. /// Must be virtual, because of call from StructuralVariety. public virtual void DetermineBehavior() { } #endregion #region Public methods /// Makes a deep copy of the BinaryStructure object. /// Returns object. [JetBrains.Annotations.PureAttribute] public override object Clone() { return new BinaryStructure(this.GSystem, this.GetStructuralCode); } /// /// Determine and sets the level property. /// /// Given bit of the structure. /// Returns level containing the given bit. public byte LevelOfBit(byte givenBit) { if (givenBit == 0) { return 0; } var bitLevel = -1; //// byte order = this.GSystem.Order; for (byte e = 0; e <= givenBit; e++) { if (this.IsOn(e)) { bitLevel++; } } var lev = (byte)((bitLevel >= 0) ? bitLevel : 0); return lev; } /// Determine and sets the level property. public void DetermineLevel() { this.level = this.IsOnInRange(0, (byte)(this.GSystem.Order - 1)); this.Properties[GenProperty.Level] = this.level; // used with Qualifiers } #endregion #region Bit gettings /// Gets a value indicating whether is the bit ON. /// Element of system. /// Returns value. public bool IsOn(byte element) { return element < this.BitArray.Count && this.BitArray[element]; } /// Gets a value indicating whether is the bit OFF. /// Requested element. /// Returns value. public bool IsOff(byte element) { if (element >= this.BitArray.Count) { return true; } return !this.BitArray[element]; } /// Returns number of bits in selected Range, that are ON. /// First element of system. /// Second element of system. /// Returns value. public byte IsOnInRange(byte elementFrom, byte elementTo) { byte s = 0; for (var e = elementFrom; e <= elementTo; e++) { if (this.IsOn(e)) { s++; } } return s; } /// Returns number of bits in selected Range, that are OFF. /// Fist element of system. /// Second element of system. /// Returns value. public byte IsOffInRange(byte elementFrom, byte elementTo) { byte s = 0; for (var e = elementFrom; e <= elementTo; e++) { if (this.IsOff(e)) { s++; } } return s; } #endregion #region Bit setting /// Sets all bits ON. public void OnAll() { this.BitArray.SetAll(true); } /// Sets selected bit ON. /// Requested element. public void On(byte element) { if (element >= this.BitArray.Length) { return; } this.BitArray[element] = true; } /// /// Sets bits in selected Range ON. /// Fist element of system. /// Second element of system. public void OnRange(byte elementFrom, byte elementTo) { for (var e = elementFrom; e <= elementTo; e++) { this.On(e); } } /// Sets all bits OFF. public void OffAll() { this.BitArray.SetAll(false); } /// Sets selected bit OFF. /// Requested element. public void Off(byte element) { if (element >= this.BitArray.Length) { return; } this.BitArray[element] = false; } /// Sets bits in selected Range OFF. /// Fist element of system. /// Second element of system. public void OffRange(byte elementFrom, byte elementTo) { for (var e = elementFrom; e <= elementTo; e++) { this.Off(e); } } #endregion #region String representation /// Binary schema of the structure. /// Returns value. public virtual string ElementString() { var s = new StringBuilder(); //// string test = this.BitArray.ToString(); for (byte e = 0; e < this.GSystem.Order; e++) { s.Append(this.IsOn(e) ? '1' : '0'); } return s.ToString(); } /// Inverse binary schema of the structure. /// Returns value. public string InverseElementString() { var s = new StringBuilder(); for (int e = (byte)(this.GSystem.Order - 1); e >= 0; e--) { s.Append(this.IsOn((byte)e) ? '1' : '0'); } return s.ToString(); } /// String representation of the object. /// Returns value. public override string ToString() { if (this.bitArray == null) { return string.Empty; } var s = new StringBuilder(); s.AppendFormat(CultureInfo.CurrentCulture, "<{0}", this.BitArray); s.AppendFormat(CultureInfo.CurrentCulture, "L{0,2}", this.level.ToString("D", CultureInfo.CurrentCulture.NumberFormat)); s.Append(" "); s.Append(this.ElementString()); //// s.Append(givenClassNumber); s.Append:this.tran; s.Append:this.rota; return s.ToString(); } #endregion #region Structural code /// Determine and sets the level property. /// Structural code. public void SetStructuralCode(string givenStructuralCode) { this.structuralCode = givenStructuralCode; this.bitArray = new BitArray(this.GSystem.Order); if (string.IsNullOrWhiteSpace(this.structuralCode)) { return; } var codes = this.structuralCode.Split(','); Array.ForEach( codes, code => { int element = byte.Parse(code, CultureInfo.CurrentCulture); if (element < this.BitArray.Length) { this.BitArray[element] = true; } }); } /// Determine and sets the level property. /// Returns value. public string DetermineStructuralCode() { var code = string.Empty; if (this.level == 0) { return code; } var places = this.BitPlaces; var first = true; foreach (var place in places) { if (first) { first = false; } else { code += ","; } code += place.ToString(CultureInfo.CurrentCulture); } return code; } #endregion #region Private methods /// /// Sets the number. /// /// The number. private void SetNumber(long number) { this.Number = number; this.bitArray = new BitArray(this.gsystem.Order); var bn = new BinaryNumber(this.gsystem, number); for (byte i = 0; i < this.gsystem.Order && i < this.BitArray.Count; i++) { this.BitArray[i] = bn.IsOn(i); } } #endregion } }